From 22f244482c53ce64d49efa3bed14e3ffb25ceb48 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sun, 19 Mar 2006 18:52:20 +0100 Subject: [PATCH] This patch fix HVM/VMX time resolution issue that cause IA32E complain "loss tick" occationally and APIC time calibration issue. Signed-off-by: Xiaowei Yang Signed-off-by: Eddie Dong --- xen/arch/x86/hvm/intercept.c | 12 ++----- xen/arch/x86/hvm/vmx/io.c | 51 ++++++++++++++++++++---------- xen/arch/x86/hvm/vmx/vmcs.c | 5 +-- xen/arch/x86/hvm/vmx/vmx.c | 28 +++++++--------- xen/include/asm-x86/hvm/domain.h | 1 + xen/include/asm-x86/hvm/vmx/vmcs.h | 1 - xen/include/asm-x86/hvm/vmx/vmx.h | 3 +- xen/include/asm-x86/hvm/vpit.h | 3 +- 8 files changed, 55 insertions(+), 49 deletions(-) diff --git a/xen/arch/x86/hvm/intercept.c b/xen/arch/x86/hvm/intercept.c index 529e1c45d7..462627dd6e 100644 --- a/xen/arch/x86/hvm/intercept.c +++ b/xen/arch/x86/hvm/intercept.c @@ -338,10 +338,10 @@ void hlt_timer_fn(void *data) static __inline__ void missed_ticks(struct hvm_virpit*vpit) { - int missed_ticks; + int missed_ticks; missed_ticks = (NOW() - vpit->scheduled)/(s_time_t) vpit->period; - if ( missed_ticks > 0 ) { + if ( missed_ticks++ >= 0 ) { vpit->pending_intr_nr += missed_ticks; vpit->scheduled += missed_ticks * vpit->period; } @@ -355,22 +355,16 @@ static void pit_timer_fn(void *data) /* pick up missed timer tick */ missed_ticks(vpit); - - vpit->pending_intr_nr++; if ( test_bit(_VCPUF_running, &v->vcpu_flags) ) { - vpit->scheduled += vpit->period; set_timer(&vpit->pit_timer, vpit->scheduled); } } +/* pick up missed timer ticks at deactive time */ void pickup_deactive_ticks(struct hvm_virpit *vpit) { - if ( !active_timer(&(vpit->pit_timer)) ) { - /* pick up missed timer tick */ missed_ticks(vpit); - - vpit->scheduled += vpit->period; set_timer(&vpit->pit_timer, vpit->scheduled); } } diff --git a/xen/arch/x86/hvm/vmx/io.c b/xen/arch/x86/hvm/vmx/io.c index 4727d65fee..1a862894ae 100644 --- a/xen/arch/x86/hvm/vmx/io.c +++ b/xen/arch/x86/hvm/vmx/io.c @@ -40,22 +40,35 @@ #define BSP_CPU(v) (!(v->vcpu_id)) -void vmx_set_tsc_shift(struct vcpu *v, struct hvm_virpit *vpit) +static inline +void __set_tsc_offset(u64 offset) { - u64 drift; - - if ( vpit->first_injected ) - drift = vpit->period_cycles * vpit->pending_intr_nr; - else - drift = 0; - vpit->shift = v->arch.hvm_vmx.tsc_offset - drift; - __vmwrite(TSC_OFFSET, vpit->shift); - + __vmwrite(TSC_OFFSET, offset); #if defined (__i386__) - __vmwrite(TSC_OFFSET_HIGH, ((vpit->shift)>> 32)); + __vmwrite(TSC_OFFSET_HIGH, offset >> 32); #endif } +u64 get_guest_time(struct vcpu *v) +{ + struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); + u64 host_tsc; + + rdtscll(host_tsc); + return host_tsc + vpit->cache_tsc_offset; +} + +void set_guest_time(struct vcpu *v, u64 gtime) +{ + struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); + u64 host_tsc; + + rdtscll(host_tsc); + + vpit->cache_tsc_offset = gtime - host_tsc; + __set_tsc_offset(vpit->cache_tsc_offset); +} + static inline void interrupt_post_injection(struct vcpu * v, int vector, int type) { @@ -64,6 +77,7 @@ interrupt_post_injection(struct vcpu * v, int vector, int type) if ( is_pit_irq(v, vector, type) ) { if ( !vpit->first_injected ) { vpit->pending_intr_nr = 0; + vpit->last_pit_gtime = get_guest_time(v); vpit->scheduled = NOW() + vpit->period; set_timer(&vpit->pit_timer, vpit->scheduled); vpit->first_injected = 1; @@ -71,7 +85,9 @@ interrupt_post_injection(struct vcpu * v, int vector, int type) vpit->pending_intr_nr--; } vpit->inject_point = NOW(); - vmx_set_tsc_shift (v, vpit); + + vpit->last_pit_gtime += vpit->period; + set_guest_time(v, vpit->last_pit_gtime); } switch(type) @@ -189,15 +205,16 @@ void vmx_do_resume(struct vcpu *v) vmx_stts(); + /* pick up the elapsed PIT ticks and re-enable pit_timer */ + if ( vpit->first_injected) { + set_guest_time(v, v->domain->arch.hvm_domain.guest_time); + pickup_deactive_ticks(vpit); + } + if ( test_bit(iopacket_port(v), &d->shared_info->evtchn_pending[0]) || test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags) ) hvm_wait_io(); - /* pick up the elapsed PIT ticks and re-enable pit_timer */ - if ( vpit->first_injected ) - pickup_deactive_ticks(vpit); - vmx_set_tsc_shift(v, vpit); - /* We can't resume the guest if we're waiting on I/O */ ASSERT(!test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags)); } diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index e612c1035d..a4e09344c4 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -195,7 +195,6 @@ static void vmx_do_launch(struct vcpu *v) /* Update CR3, GDT, LDT, TR */ unsigned int error = 0; unsigned long cr0, cr4; - u64 host_tsc; if (v->vcpu_id == 0) hvm_setup_platform(v->domain); @@ -250,9 +249,7 @@ static void vmx_do_launch(struct vcpu *v) v->arch.hvm_vmx.launch_cpu = smp_processor_id(); /* init guest tsc to start from 0 */ - rdtscll(host_tsc); - v->arch.hvm_vmx.tsc_offset = 0 - host_tsc; - vmx_set_tsc_shift(v, &v->domain->arch.hvm_domain.vpit); + set_guest_time(v, 0); } /* diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 19708dde97..191344e835 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -354,8 +354,18 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) #endif /* __i386__ */ +static void vmx_freeze_time(struct vcpu *v) +{ + struct hvm_virpit *vpit = &v->domain->arch.hvm_domain.vpit; + + v->domain->arch.hvm_domain.guest_time = get_guest_time(v); + if ( vpit->first_injected ) + stop_timer(&(vpit->pit_timer)); +} + static void vmx_ctxt_switch_from(struct vcpu *v) { + vmx_freeze_time(v); vmx_save_segments(v); vmx_load_msrs(); } @@ -1707,7 +1717,7 @@ static inline void vmx_do_msr_read(struct cpu_user_regs *regs) rdtscll(msr_content); vpit = &(v->domain->arch.hvm_domain.vpit); - msr_content += vpit->shift; + msr_content += vpit->cache_tsc_offset; break; } case MSR_IA32_SYSENTER_CS: @@ -1751,22 +1761,8 @@ static inline void vmx_do_msr_write(struct cpu_user_regs *regs) switch (regs->ecx) { case MSR_IA32_TIME_STAMP_COUNTER: - { - struct hvm_virpit *vpit; - u64 host_tsc, drift; - - rdtscll(host_tsc); - vpit = &(v->domain->arch.hvm_domain.vpit); - drift = v->arch.hvm_vmx.tsc_offset - vpit->shift; - vpit->shift = msr_content - host_tsc; - v->arch.hvm_vmx.tsc_offset = vpit->shift + drift; - __vmwrite(TSC_OFFSET, vpit->shift); - -#if defined (__i386__) - __vmwrite(TSC_OFFSET_HIGH, ((vpit->shift)>>32)); -#endif + set_guest_time(v, msr_content); break; - } case MSR_IA32_SYSENTER_CS: __vmwrite(GUEST_SYSENTER_CS, msr_content); break; diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h index 812f91d76d..ee44cfeb3d 100644 --- a/xen/include/asm-x86/hvm/domain.h +++ b/xen/include/asm-x86/hvm/domain.h @@ -37,6 +37,7 @@ struct hvm_domain { unsigned int pae_enabled; struct hvm_virpit vpit; + u64 guest_time; struct hvm_virpic vpic; struct hvm_vioapic vioapic; struct hvm_io_handler io_handler; diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h index f79f7a4c8b..c77e665463 100644 --- a/xen/include/asm-x86/hvm/vmx/vmcs.h +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h @@ -77,7 +77,6 @@ struct arch_vmx_struct { unsigned long cpu_based_exec_control; struct vmx_msr_state msr_content; void *io_bitmap_a, *io_bitmap_b; - u64 tsc_offset; struct timer hlt_timer; /* hlt ins emulation wakeup timer */ }; diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h index f4429f3dbe..3c34cdf8ac 100644 --- a/xen/include/asm-x86/hvm/vmx/vmx.h +++ b/xen/include/asm-x86/hvm/vmx/vmx.h @@ -30,10 +30,11 @@ extern void vmx_asm_vmexit_handler(struct cpu_user_regs); extern void vmx_asm_do_resume(void); extern void vmx_asm_do_launch(void); extern void vmx_intr_assist(void); -extern void vmx_set_tsc_shift(struct vcpu *, struct hvm_virpit *); extern void vmx_migrate_timers(struct vcpu *v); extern void arch_vmx_do_launch(struct vcpu *); extern void arch_vmx_do_resume(struct vcpu *); +extern void set_guest_time(struct vcpu *v, u64 gtime); +extern u64 get_guest_time(struct vcpu *v); extern unsigned int cpu_rev; diff --git a/xen/include/asm-x86/hvm/vpit.h b/xen/include/asm-x86/hvm/vpit.h index a29e50c2ef..0b955b470c 100644 --- a/xen/include/asm-x86/hvm/vpit.h +++ b/xen/include/asm-x86/hvm/vpit.h @@ -38,7 +38,6 @@ struct hvm_virpit { /* for simulation of counter 0 in mode 2 */ u64 period_cycles; /* pit frequency in cpu cycles */ - u64 shift; /* save the value of offset - drift */ s_time_t inject_point; /* the time inject virt intr */ s_time_t scheduled; /* scheduled timer interrupt */ struct timer pit_timer; /* periodic timer for mode 2*/ @@ -46,6 +45,8 @@ struct hvm_virpit { unsigned int pending_intr_nr; /* the couner for pending timer interrupts */ u32 period; /* pit frequency in ns */ int first_injected; /* flag to prevent shadow window */ + s64 cache_tsc_offset; /* cache of VMCS TSC_OFFSET offset */ + u64 last_pit_gtime; /* guest time when last pit is injected */ /* virtual PIT state for handle related I/O */ int read_state; -- 2.30.2